import 'dart:async';

import 'package:rxdart/rxdart.dart';

import '../../common/test_page.dart';

class TimerTestPage extends TestPage {
  TimerTestPage(super.title) {
    test('TimerStream', () async {
      const value = 1;

      final stream = TimerStream(value, Duration(milliseconds: 1));

      expect(stream);
    });

    test('TimerStream.single.subscription', () async {
      final stream = TimerStream(1, Duration(milliseconds: 1));

      stream.listen(null);
      expect(() => stream.listen(null));
    });

    test('TimerStream.pause.resume.A', () async {
      const value = 1;
      late StreamSubscription<int> subscription;

      final stream = TimerStream(value, Duration(milliseconds: 1));

      subscription = stream.listen(((actual) {
        expect('$actual, $value');

        subscription.cancel();
      }));

      subscription.pause();
      subscription.resume();
    });

    test('TimerStream.pause.resume.B', () async {
      const seconds = 2;
      const delay = 1;

      var stream = Rx.timer(99, const Duration(seconds: seconds));
      var stopwatch = Stopwatch()..start();
      var subscription = stream.listen(((_) {
        stopwatch.stop();
        expect('${stopwatch.elapsed.inSeconds}, ${seconds + delay}');
      }));

      await Future<void>.delayed(const Duration(milliseconds: 100));
      subscription.pause();
      subscription.pause();

      await Future<void>.delayed(const Duration(seconds: delay));

      subscription.resume();
      subscription.resume();
      subscription.resume();
    });

    test('TimerStream.pause.resume.C', () async {
      const value = 1;
      const delta = Duration(milliseconds: 100);
      const duration = Duration(seconds: 1);
      final stream = TimerStream(value, duration);

      var elapses = Duration.zero;
      late Stopwatch watch;

      void startWatch() => watch = Stopwatch()..start();

      Future<void> delay() =>
          Future<void>.delayed(const Duration(milliseconds: 200));

      void stopWatch() => elapses = elapses + watch.elapsed;

      final subscription = stream.listen(((actual) {
        expect('$actual, $value');

        stopWatch();
        expect(
          duration - delta <= elapses && elapses <= duration + delta
        );
      }));
      startWatch();

      await delay();

      subscription.pause();
      stopWatch();

      await delay();

      subscription.resume();
      startWatch();
    });

    test('TimerStream.single.subscription', () async {
      final stream = TimerStream(null, Duration(milliseconds: 1));

      try {
        stream.listen(null);
        stream.listen(null);
      } catch (e) {
        expect(e);
      }
    });

    test('TimerStream.cancel', () async {
      const value = 1;
      StreamSubscription<int> subscription;

      final stream = TimerStream(value, Duration(milliseconds: 1));

      subscription = stream.listen(
          ((_) {
            expect(true,);
          }),
          onError: (Object e, StackTrace s) {
            expect(true,);
          },
          onDone: (() {
            expect(true);
          }));

      await subscription.cancel();
    });

    test('Rx.timer', () async {
      const value = 1;

      final stream = Rx.timer(value, Duration(milliseconds: 5));

      stream.listen(((actual) {
        expect('$actual, $value');
      }), onDone: (() {
        expect(true);
      }));
    });
  }

}